package com.lenovo.flutter_with_bmap;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.util.Log;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BitmapDescriptor;
import com.baidu.mapapi.map.BitmapDescriptorFactory;
import com.baidu.mapapi.map.MapStatus;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.Marker;
import com.baidu.mapapi.map.MarkerOptions;
import com.baidu.mapapi.model.LatLng;
import com.lenovo.flutter_with_bmap.consts.MsgType;
import com.lenovo.flutter_with_bmap.consts.VehicleTypeEnum;
import com.lenovo.flutter_with_bmap.entity.CacheData;
import com.lenovo.flutter_with_bmap.entity.MapCreationParams;
import com.lenovo.flutter_with_bmap.entity.Vehicle;
import com.lenovo.flutter_with_bmap.util.GpsHandle;
import com.lenovo.flutter_with_bmap.util.ListenerHelper;
import com.lenovo.flutter_with_bmap.util.WebSocketHelper;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.platform.PlatformView;

public class BMapView implements PlatformView, DefaultLifecycleObserver,MethodChannel.MethodCallHandler {
    private MapView mapView;
    private BaiduMap baiduMap;
    private FlutterPluginBinding flutterPluginBinding;
    private ActivityPluginBinding activityPluginBinding;
    private Object mapParams;
    private BitmapDescriptor icon_car;
    private BitmapDescriptor icon_truck;
    private BitmapDescriptor icon_bus;
    private BitmapDescriptor icon_emergency_vehicle;
    private BitmapDescriptor icon_bicycle;
    private BitmapDescriptor icon_person;
    private BitmapDescriptor icon_hv;
    private String channel_name = "BMapOperate";
    private MethodChannel methodChannel;
    private ConcurrentMap<String, CacheData> cacheData = new ConcurrentHashMap<>();
    private CacheData vehicle_hv;
    private Timer clearMarkerTimer = new Timer();
    private WebSocketHelper webSocketHelper;
    private static final String SHARED_PREFERENCES_NAME = "FlutterSharedPreferences";
    private static final String prefix = "flutter.";
    private SharedPreferences sharedPreferences;
    public BMapView(ActivityPluginBinding activityPluginBinding, FlutterPluginBinding flutterPluginBinding, @Nullable Object args){
        this.flutterPluginBinding = flutterPluginBinding;
        this.activityPluginBinding = activityPluginBinding;
        this.mapParams = args;
        init();
    }
    @Nullable
    @Override
    public View getView() {
        return mapView;
    }

    @Override
    public void dispose() {

    }

    @Override
    public void onCreate(@NonNull LifecycleOwner owner) {
    }

    @Override
    public void onResume(@NonNull LifecycleOwner owner) {
        if(mapView!=null){
            mapView.onResume();
        }
    }

    @Override
    public void onPause(@NonNull LifecycleOwner owner) {
        if(mapView!=null){
            mapView.onPause();
        }
    }

    @Override
    public void onDestroy(@NonNull LifecycleOwner owner) {
        if(mapView!=null){
            mapView.onDestroy();
        }
        webSocketHelper.close();
    }
    private void init(){
        FlutterActivity flutterActivity = (FlutterActivity) activityPluginBinding.getActivity();
        flutterActivity.getLifecycle().addObserver(this);
        methodChannel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(),channel_name);
        methodChannel.setMethodCallHandler(this);
        sharedPreferences = flutterActivity.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
        initIcons();
        initMapView();
        initWebSocket();
    }
    private void initWebSocket() {
        webSocketHelper = new WebSocketHelper();
        webSocketHelper.connect("ws://bamboo-os.org:6310");
//        webSocketHelper.connect("ws://192.168.20.70:8000");
        webSocketHelper.addListener(new ListenerHelper() {
            @Override
            public void callBack(String msg) {
                Map json = JSON.parseObject(msg);
                int tag = (int) json.get("tag");
                activityPluginBinding.getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if(tag == MsgType.vehicle_hv.getnCode()){
                            //设置主车信息
                            Vehicle vehicle = JSON.parseObject(json.get("data").toString(),Vehicle.class);
                            double[] latlng = GpsHandle.wgs2bd(vehicle.getLatitude(),vehicle.getLongitude());
                            vehicle.setLatitude(latlng[0]);
                            vehicle.setLongitude(latlng[1]);
                            setVehicleInfo(vehicle);
                            setMapStatus(vehicle);
                            methodChannel.invokeMethod(MsgType.vehicle_hv.toString(), json.get("data").toString());
                        }else if (tag == MsgType.participant.getnCode()){
                            //设置交通参与者
                            JSONArray arrayList = (JSONArray) json.get("data");
                            for (Object hashMap :  arrayList){
                                Vehicle vehicle = JSON.parseObject(JSON.toJSONString(hashMap),Vehicle.class);
                                double[] latlng = GpsHandle.wgs2bd(vehicle.getLatitude(),vehicle.getLongitude());
                                vehicle.setLatitude(latlng[0]);
                                vehicle.setLongitude(latlng[1]);
                                drawParticipant(vehicle);
                            }
                        }else if (tag == MsgType.light_hv.getnCode()){
                            methodChannel.invokeMethod(MsgType.light_hv.toString(), json.get("data").toString());
                        }else if(tag == MsgType.alarm.getnCode()){
                            methodChannel.invokeMethod(MsgType.alarm.toString(), json.get("data").toString());
                        }else if(tag == MsgType.green_wave.getnCode()){
                            methodChannel.invokeMethod(MsgType.green_wave.toString(), json.get("data").toString());
                        }
                    }
                });

            }
        });
        clearInternally();
    }
    private void initMapView(){
        FlutterActivity flutterActivity = (FlutterActivity)activityPluginBinding.getActivity();
        String str = JSON.toJSONString(mapParams);
        MapCreationParams params = JSON.parseObject(str,MapCreationParams.class);
        LatLng center = new LatLng( params.getCenter().get(0), params.getCenter().get(1));
        MapStatus mapStatus = new MapStatus.Builder().target(center).zoom(params.getZoom()).build();
        MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mapStatus);
        mapView = new MapView(flutterActivity);
        baiduMap = mapView.getMap();
        String mapType = sharedPreferences.getString(prefix + "settings.mapMode","normal");
        baiduMap.setMapType(mapType.equals("normal")?BaiduMap.MAP_TYPE_NORMAL:BaiduMap.MAP_TYPE_SATELLITE);
        baiduMap.setMapStatus(mapStatusUpdate);
//        baiduMap.setOnMarkerClickListener(new BaiduMap.OnMarkerClickListener() {
//            @Override
//            public boolean onMarkerClick(Marker marker) {
//                Bundle bundle = marker.getExtraInfo();
//                MapStatus mapStatus = new MapStatus.Builder().target(new LatLng(bundle.getDouble("lat"),bundle.getDouble("lng"))).zoom(18).build();
//                MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mapStatus);
//                baiduMap.animateMapStatus(mapStatusUpdate);
//                LatLngBounds bounds = baiduMap.getMapStatusLimit();
//                Log.e("地图的边界坐标",bounds.toString());
//                methodChannel.invokeMethod("subscribeParticipant", JSON.toJSON(bounds), new MethodChannel.Result() {
//                    @Override
//                    public void success(@Nullable Object result) {
//                        clearInternally();
//                    }
//
//                    @Override
//                    public void error(@NonNull String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) {
//                    }
//
//                    @Override
//                    public void notImplemented() {
//                    }
//                });
//                return false;
//            }
//        });
//        baiduMap.setOnMapStatusChangeListener(new BaiduMap.OnMapStatusChangeListener() {
//            @Override
//            public void onMapStatusChangeStart(MapStatus mapStatus) {
//
//            }
//
//            @Override
//            public void onMapStatusChangeStart(MapStatus mapStatus, int i) {
//
//            }
//
//            @Override
//            public void onMapStatusChange(MapStatus mapStatus) {
//
//            }
//
//            @Override
//            public void onMapStatusChangeFinish(MapStatus mapStatus) {
//                float zoom =  mapStatus.zoom;
//                if(zoom>18){
//
//                }else {
//
//                }
//            }
//        });
    }
    private void initIcons(){
        //获取文件资源放进子线程，不要阻塞UI线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                icon_car = iconMaker("flutter_assets/images/markers/car.png",50,98);
                icon_truck = iconMaker("flutter_assets/images/markers/truck.png",45,148);
                icon_bus = iconMaker("flutter_assets/images/markers/bus.png",45,105);
                icon_emergency_vehicle = iconMaker("flutter_assets/images/markers/emergency.png",40,86);
                icon_bicycle = iconMaker("flutter_assets/images/markers/bicycle.png",20,55);
                icon_person = iconMaker("flutter_assets/images/markers/person.png",64,64);
                icon_hv = iconMaker("flutter_assets/images/markers/hv.png",60,60);
            }
        }).start();
    }
    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        String mtd = call.method;Object args = call.arguments;
        if(mtd.equals("setMapType")){
            baiduMap.setMapType(args.equals("normal")?BaiduMap.MAP_TYPE_NORMAL:BaiduMap.MAP_TYPE_SATELLITE);
        }
    }
    private void setVehicleInfo(Vehicle vehicle){
        LatLng pointer = new LatLng(vehicle.getLatitude(),vehicle.getLongitude());
        float mapRotate = baiduMap.getMapStatus().rotate;
        double rotate = vehicle.getHead();
        String angleOfView = sharedPreferences.getString(prefix + "settings.angleOfView","map");
        float vehicleR =  angleOfView.equals("vehicle")?0:(float) (mapRotate - rotate);
        if(vehicle_hv == null){
            MarkerOptions markerOptions = new MarkerOptions().position(pointer).icon(icon_hv).rotate(vehicleR).anchor(0.5f,0.5f);
            Marker marker = (Marker) baiduMap.addOverlay(markerOptions);
            vehicle_hv = new CacheData(vehicle,marker,System.currentTimeMillis());
        }else {
            vehicle_hv.setTimeStamp(System.currentTimeMillis());
            Marker marker = vehicle_hv.getMarker();
            marker.setPosition(pointer);
            marker.setRotate(vehicleR);
            marker.setAnchor(0.5f,0.5f);
            vehicle_hv.setData(vehicle);
        }
    }
    private void setMapStatus(Vehicle vehicle){
        boolean mapFollow = sharedPreferences.getBoolean(prefix + "settings.mapFollow",false);
        String angleOfView = sharedPreferences.getString(prefix + "settings.angleOfView","map");
        MapStatus.Builder builder = new MapStatus.Builder();
        //地图跟随
        if(mapFollow){
            LatLng center = new LatLng(vehicle.getLatitude(),vehicle.getLongitude());
            builder.target(center);
        }
        //车辆视角，车子一直是朝着北方的，地图转动
        if(angleOfView.equals("vehicle")){
            builder.rotate((float) vehicle.getHead());
        }
        MapStatusUpdate mapStatusUpdate = MapStatusUpdateFactory.newMapStatus(builder.build());
        baiduMap.animateMapStatus(mapStatusUpdate);
    }

//    private void drawOrgs(ArrayList<Organization> data){
//        for (Organization org : data){
//            Bundle bundle = new Bundle();
//            bundle.putString("organization",org.getOrganization());
//            bundle.putDouble("lat",org.getLatitude());
//            bundle.putDouble("lng",org.getLongitude());
//            MarkerOptions markerOptions = new MarkerOptions().position(new LatLng(org.getLatitude(),org.getLongitude()))
//                    .extraInfo(bundle)
//                    .icon(icon_organization).anchor(0.5f,0.5f);
//            baiduMap.addOverlay(markerOptions);
//        }
//    }
    private void drawParticipant(Vehicle participant){
        LatLng pointer = new LatLng(participant.getLatitude(),participant.getLongitude());
        float mapRotate = baiduMap.getMapStatus().rotate;
        double rotate = participant.getHead();
        BitmapDescriptor icon = getMarkerIcon(participant);
        CacheData data = cacheData.get(participant.getVehicleId());
        if(data == null){
            MarkerOptions markerOptions = new MarkerOptions().position(pointer).icon(icon).rotate((float) (mapRotate-rotate)).anchor(0.5f,0.5f);
            Marker marker = (Marker) baiduMap.addOverlay(markerOptions);
            cacheData.put(participant.getVehicleId(),new CacheData(participant,marker,System.currentTimeMillis()));
        }else {
            data.setTimeStamp(System.currentTimeMillis());
            Marker marker = data.getMarker();
            marker.setPosition(pointer);
            marker.setRotate((float) (mapRotate-rotate));
            marker.setIcon(icon);
            marker.setAnchor(0.5f,0.5f);
            data.setData(participant);
        }
    }
    private void clearInternally(){
        clearMarkerTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                Iterator<String> iterator = cacheData.keySet().iterator();
                while (iterator.hasNext()){
                    String key = iterator.next();
                    CacheData data = cacheData.get(key);
                    if(System.currentTimeMillis() - data.getTimeStamp()>2000){
                        baiduMap.removeOverLays(Arrays.asList(data.getMarker()));
                        iterator.remove();
                    }
                }
            }
        },0,200);
    }
    private BitmapDescriptor getMarkerIcon(Vehicle participant){
        BitmapDescriptor bitmapDescriptor = icon_car;
        int type = participant.getVehicleType();
        if(type == VehicleTypeEnum.PERSION.getnCode()){
            bitmapDescriptor = icon_person;
        }else if(type == VehicleTypeEnum.NONVEHICLE.getnCode()){
            bitmapDescriptor = icon_bicycle;
        }else if(type == VehicleTypeEnum.VEHICLE.getnCode()){
            bitmapDescriptor = icon_car;
        }else if(type == VehicleTypeEnum.CAR.getnCode()){
            bitmapDescriptor = icon_car;
        }else if(type == VehicleTypeEnum.BUS.getnCode()){
            bitmapDescriptor = icon_bus;
        }else if(type == VehicleTypeEnum.TRUCK.getnCode()){
            bitmapDescriptor = icon_truck;
        }else if(type == VehicleTypeEnum.EMERGENCY.getnCode()){
            bitmapDescriptor = icon_emergency_vehicle;
        }
        return  bitmapDescriptor;
    }
    private BitmapDescriptor iconMaker(String filePath,int width,int height){
        String path = flutterPluginBinding.getFlutterAssets().getAssetFilePathBySubpath(filePath);
        AssetManager assetManager = flutterPluginBinding.getApplicationContext().getAssets();
        InputStream inputStream  = null;
        try {
            //只有这个方式图片加载进来了，openfd方法加载进来之后初始化bitmap始终是null不知道为啥
            inputStream = assetManager.open(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
        int _width = bitmap.getWidth(),_height = bitmap.getHeight();
        float scaleWidth = 1.0f*width/_width,scaleHeight = 1.0f*height/_height;
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth,scaleHeight);
        Bitmap bitmap1 = Bitmap.createBitmap(bitmap,0,0,_width,_height,matrix,true);
        BitmapDescriptor bitmap2 = BitmapDescriptorFactory.fromBitmap(bitmap1);
        return  bitmap2;
    }
}
